package com.doupi.partner.util;

import com.alibaba.fastjson.JSON;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 对象工具类
 *
 * @author Super Jens Wang
 * @version 1.0 @ 2016年7月20日 上午5:13:49
 */
public class ObjectUtils {
    private final static Logger LOGGER = LoggerFactory.getLogger(ObjectUtils.class);
    private final static String SERIAL_VERSION_UID = "serialVersionUID";

    /**
     * 将源对象转换成目标对象
     *
     * @param source - 源对象
     * @param clazz  - 目标对象的类
     * @return T - 目标对象
     */
    public static <T> T convertSourceToTarget(Object source, Class<T> clazz) {
        T target;
        try {
            target = clazz.newInstance();
            BeanUtils.copyProperties(target, source);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return target;
    }

    /**
     * 将Map对象转换成指定的类对象，该类必须是public的类
     *
     * @param map   - map数据
     * @param clazz - 将要把map转换成的目标类
     * @return T - 目标类
     */
    public static <T> T parseMapToObject(Map<String, String> map, Class<T> clazz) {
        T obj;
        try {
            obj = clazz.newInstance();
            BeanUtils.populate(obj, map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return obj;
    }

    /**
     * 使用JSON转换MAP到Bean
     */
    public static <T> T parseMapToObjectWithJson(Map<String, String> map, Class<T> clazz) {
        String json = JSON.toJSONString(map);
        return JSON.parseObject(json, clazz);
    }

    /**
     * 将bean转为map
     */
    public static Map<String, String> parseObjectToMap(Object bean) {
        try {
            Map<String, String> map = BeanUtils.describe(bean);
            map.remove("class");
            return map;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将bean转为map
     */
    public static Map<String, String> parseObjectToMapWithField(Object bean, boolean ignoreNull, boolean trimNullToEmpty) {
        try {
            Map<String, String> map = new HashMap<String, String>();
            Field[] fields = FieldUtils.getAllFields(bean.getClass());
            for (Field field : fields) {
                String name = field.getName();
                if (StringUtils.equalsIgnoreCase(SERIAL_VERSION_UID, name)) {
                    continue;
                }
                Object value = FieldUtils.readField(field, bean, true);
                if (ignoreNull && null == value) {
                    continue;
                }
                if (trimNullToEmpty && null == value) {
                    value = StringUtils.EMPTY;
                }
                map.put(name, null == value ? null : value.toString());
            }
            return map;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将bean转为map
     */
    public static Map<String, String> parseObjectToMapWithField(Object bean) {
        return parseObjectToMapWithField(bean, true, true);
    }

    /**
     * 将bean转换为另一个bean
     */
    public static <T> T parseObjectToAnotherObjectWithJson(Object obj, Class<T> clazz) {
        String json = JSON.toJSONString(obj);
        return JSON.parseObject(json, clazz);
    }

    /**
     * 复制属性
     */
    public static void copyProperties(Object dest, Object orig) {
        try {
            BeanUtils.copyProperties(dest, orig);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 复制属性 非空值跳过
     */
    public static void copyProperties(Object dest, Object orig, boolean notNullSkip) {
        if (notNullSkip) {
            try {
                Map<String, String> fields = BeanUtils.describe(dest);
                for (String field : fields.keySet()) {
                    if (!StringUtils.equals("class", field) && !StringUtils.isNotBlank(fields.get(field))) {
                        try {
                            Object origValue = BeanUtils.getSimpleProperty(orig, field);
                            BeanUtils.copyProperty(dest, field, origValue);
                        } catch (NoSuchMethodException e) {
                            // Should not happen
                        }
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            copyProperties(dest, orig);
        }
    }

    /**
     * 复制属性 非空值跳过 以orig为准
     */
    public static void copyProperties(Object dest, Object orig, boolean notNullSkip, boolean nullSkip) {
        if (notNullSkip && !nullSkip) {
            copyProperties(dest, orig, true);
        } else if (nullSkip) {
            try {
                Map<String, String> fields = BeanUtils.describe(dest);
                for (String field : fields.keySet()) {
                    if (!StringUtils.equals("class", field) && (!StringUtils.isNotBlank(fields.get(field)))) {
                        try {
                            String origValue = BeanUtils.getSimpleProperty(orig, field);
                            if (StringUtils.isNotBlank(origValue)) {
                                BeanUtils.copyProperty(dest, field, origValue);
                            }
                        } catch (NoSuchMethodException e) {
                            // Should not happen
                        }
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            copyProperties(dest, orig);
        }
    }

    /**
     * 设置字段值
     */
    public static void setProperty(Object object, String name, Object value) {
        try {
            BeanUtils.setProperty(object, name, value);
        } catch (Exception e) {
            // ignore should not be appear
            // LOGGER.error("设置属性失败object={}, name={}， value={}", object, name, value, e);
        }
    }

    /**
     * 设置字段值
     */
    public static void setFieldValue(Object object, String name, Object value) {
        try {
            FieldUtils.writeField(object, name, value, true);
        } catch (Exception e) {
            // ignore should not be appear
            // LOGGER.error("设置字段失败object={}, name={}， value={}", object, name, value, e);
        }
    }

    /**
     * 获取字段值
     */
    public static Object getFieldValue(Object object, String name) {
        try {
            return FieldUtils.readField(object, name, true);
        } catch (Exception e) {
            // ignore
            // LOGGER.error("获取字段失败object={}, name={}", object, name, e);
        }
        return null;
    }

    /**
     * 设置字段值
     */
    public static Object getProperty(Object object, String name) {
        try {
            return BeanUtils.getProperty(object, name);
        } catch (Exception e) {
            // ignore
            // LOGGER.error("获取属性失败object={}, name={}， value={}", object, name, e);
        }
        return null;
    }

    /**
     * 创建对象
     */
    public static <T> T newInstance(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            // ignore
        }
        return null;
    }

    /**
     * 转换httpSevelet请求
     */
    public static <Response> Response convertFromRequest(HttpServletRequest request, Class<Response> clazz) {
        Response response = newInstance(clazz);
        Field[] fields = FieldUtils.getAllFields(clazz);

        for (Field field : fields) {
            String name = field.getName();
            if (StringUtils.equalsIgnoreCase(SERIAL_VERSION_UID, name)) {
                continue;
            }

            String value = request.getParameter(name);

            if (null != value) {
                value = urlDecode(value);
                ObjectUtils.setFieldValue(response, name, value);
            }
        }

        return response;
    }

    /**
     * url encode
     */
    public static String urlEncode(final String forEncodeString) {
        try {
            String enc = System.getProperty("file.encoding");
            LOGGER.info("系统编码：{}", enc);
            return URLEncoder.encode(forEncodeString, enc);
        } catch (UnsupportedEncodingException e) {
            LOGGER.error("url编码失败", e);
            throw new RuntimeException("url编码失败", e);
        }
    }

    /**
     * url decode
     */
    public static String urlDecode(final String forDecodeString) {
        try {
            String enc = System.getProperty("file.encoding");
            LOGGER.info("系统编码：{}", enc);
            return URLDecoder.decode(forDecodeString, enc);
        } catch (UnsupportedEncodingException e) {
            LOGGER.error("url解码失败", e);
            throw new RuntimeException("url解码失败", e);
        }
    }
}
